package ccpv;

import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import multiarray.MultiArray;

public class Utilities {

	/**
	 * Debugging function used to generator 100 normally distributed numbers to a file.
	 * @param mean
	 * @param stdDev
	 */
	public static void generateGaussian(double mean, double stdDev) {
		
		FileWriter outfile;
		try {
			outfile = new FileWriter("output.csv");
			Random generator = new Random();
			for (int i = 0; i<100; i++) {
		  	  outfile.write(Double.toString(normalRandom(generator, mean,stdDev)));
		  	  outfile.write("\r\n");
			}
		} catch (IOException e) {

			e.printStackTrace();
		}

	
	}
	

	/**
	 * Generates a random number with normal distribution using the supplied random generator, mean, and standard deviation.
	 * @param generator The random generator to be used.
	 * @param mean The mean of the normal distribution.
	 * @param stdDev The standard deviation of the normal distribution.
	 * @return A random number in the normal distribution specified.
	 */
	public static double normalRandom(Random generator, double mean, double stdDev) {
		return generator.nextGaussian()*stdDev+mean;	
	}

	/**
	 * Generates a random number with normal distribution using the supplied mean and standard deviation.
	 * @param mean The mean of the normal distribution.
	 * @param stdDev The standard deviation of the normal distribution.
	 * @return A random number in the normal distribution specified.
	 */
	public static double normalRandom(double mean, double stdDev) {
		Random generator = new Random();
		return generator.nextGaussian()*stdDev+mean;	
	}
	
	
	
	/**
	 * Generates the initial population of people for the first year specified in the runtime settings.
	 * @param rt
	 * @return
	 */
	public static MultiArray<Person> makePeople(RunTimeSettings rt) {
		return makePeople(rt,rt.getYears()[0]);
	}

	public static MultiArray<Person> makePeople(RunTimeSettings rt, int year) {
		int qty = 0;
		double power = 0.0;
		int[] dims = rt.getAscriptiveLengths();
		MultiArray<Person> people = new MultiArray<Person>(dims);
		MultiArray<Double> alt;
		
		Person p;
	    List<int[]> groupChars = multiarray.RecursiveAccess.generateAllPermutations(dims);

		for (int[] gchar: groupChars) {
			alt = new MultiArray<Double>(dims);
			qty = rt.getPopulation(year, gchar);
			power = rt.getValue(year, gchar, 0);
			for (int[] gchar2: groupChars) {
				double val = rt.getAltruism(gchar, gchar2, year);
				alt.setElementAtIndex(gchar2, val);
			}
			//int[] character, int qty, int location, int power
			p = new Person(gchar, qty, 0, power);
			p.setAltruism(alt, dims);
			people.setElementAtIndex(gchar, p);
		}
		
		return people;
	}
	
	/*
	/**
	 * Generates num quantity of people with the ascriptive characteristics specified in features.
	 * @param features ascriptive characteristic index list
	 * @param location
	 * @param num
	 * @return
	 
	public static ArrayList<Person> makePeople(int[] features, int location, int num) {
		
		ArrayList<Person> people = new ArrayList<Person>();
		Person p1;
			
		for (int j = 0; j < num; j++) {
			 //Person(int[] character, int qty, int location, int groupIndex) 
	      p1 = new Person(features,location);
	      people.add(p1);
		}
		 
		return people;
	}
	*/
	
	/**
	 * Updates the agent population to have the quantity of people specified for each group in the runtime settings for the specified year. 
	 * @param rt
	 * @param population
	 * @param year
	 */
	public static void updateAgentPopulation(RunTimeSettings rt, ArrayList<Person> population, int year) {
		int newValue;
		for (int i = 0; i<population.size(); i++) {
			newValue = rt.getPopulation(year,population.get(i).getCharacter());
			int curr = population.get(i).getQty();
			System.out.println("Old: "+curr+"  New: " + newValue);
			population.get(i).setQty(newValue);
			
			/*if (newValue == curr) continue;
			if (newValue <0) continue;
			
			
			if (newValue < curr) {
				while (population.get(i).size() != newValue) {
					population.get(i).remove(0);
				}
			} else {
				while (population.get(i).size() != newValue) {
				//	if ((population.get(i).size() % 1000)==0) System.out.println(population.get(i).size());
					if (population.get(i).size() == 0) {
						population.get(i).add(new Person(rt.getEpochs().get(i).getCharacteristics(),rt.getEpochs().get(i).getGeolocation())); 

						population.get(i).add(new Person(rt.getEpochs().get(i).getCharacteristics(),rt.getEpochs().get(i).getGeolocation())); 
					} else {
					  population.get(i).add(new Person(population.get(i).get(0))); // needs to be improved
					}
				}
			}
			*/
		}
	}
	

	
	public static Point2D generateRandomInArea(Area area1) {
		Rectangle2D bounds1 = area1.getBounds2D();
		Random rand1 = new Random();
		int counter = 0;
		double x,y;
		do {
		  counter++;
	  	  x = rand1.nextDouble()*bounds1.getWidth()+bounds1.getX();
		  y = rand1.nextDouble()*bounds1.getHeight()+bounds1.getY();
		}
		while (!area1.contains(x, y));
		
		System.out.println("# trials: "+counter);
		
		return new Point2D.Double(x,y);
		
	}
	
	public static Area buildAreaFromPoints(ArrayList<Point2D> points) {
		
		Path2D.Double path1 = new Path2D.Double();
		
		if (!points.isEmpty()){
		  Iterator<Point2D> itr = points.iterator();
		  Point2D start = itr.next();
		  Point2D temp = null;
		  path1.moveTo(start.getX(), start.getY());
		    while (itr.hasNext()) {
		      temp = itr.next();
		      path1.lineTo(temp.getX(), temp.getY());
		    }
		  path1.lineTo(start.getX(), start.getY());
		}

		Area result = new Area(path1);
		path1.closePath();
		assert result.isPolygonal();
		return result;
		
	}
	



}
